---@diagnostic disable: trailing-space
local desc_kfzy = [[

# 克复中原 模式简介
兴服大汉，在此九伐！主公需要在九轮内击败所有反贼，反贼会在死亡后“归服”，即在下一轮开始时变为忠臣，协助主公击败反贼。反贼方需要击败主公，或至少一人存活至第九轮结束时即可获胜。

___

## 基本规则:

**1.玩家设定：**
人数4-8人。一号位玩家身份为主公，其余玩家身份为反贼，按座次依次行动。

**2.开局设定：**
【选将】主公只能选择蜀国（包括蜀副势力）武将，其他角色不能选择蜀国武将（包括蜀副势力），若选择神势力，随机选择非蜀势力。
【手牌】主公的初始手牌为（4+反贼玩家数量），反贼初始手牌为3，默认无法使用手气卡
【体力】主公玩家初始体力上限为（3+场上存活反贼数），反贼玩家初始体力上限为2

**3.击杀奖惩：**
【主公】击杀一名反贼后，摸一张牌；击杀忠臣后，弃置所有牌。
【忠臣】击杀一名反贼后，主公回复一点体力。
【反贼】击杀一名忠臣后，摸等同于忠臣数量（包括死亡忠臣）的牌。

**4.死亡额外规则：**
【结党】每阵亡两名反贼，所有存活反贼加一点体力上限、回复1点体力、摸一张牌(存活玩家为4或以下时，改为每阵亡一名)
【衰伐】一名反贼阵亡后，主公失去一点体力上限，选择并失去“复汉”获得的一个技能
【归服】一名反贼阵亡后，下一轮开始时以忠臣身份重新返回游戏，体力与体力上限变更为2，摸3张牌

**5.获胜条件：**
【主公/忠臣】在第9轮结束前击杀所有反贼
【反贼】击败主公，或至少一个反贼存活至第9轮结束

**6.额外技能：**
主公：【复汉】锁定技，第一轮开始时，你重复三次：从随机的3个蜀国武将技能中选择一个获得。每轮开始时，若你已失去以此法获得的所有技能，你视为对随机一名反贼角色使用了一张【杀】。
反贼：【结患】每轮限一次，你受到其他反贼造成的伤害时，你可以弃置一张牌防止此伤害。锁定技，若你攻击范围不含主公，你的手牌上限+2。

**7.禁卡规则：**
卡牌：移除【乐不思蜀】，【兵粮寸断】
武将：移除大乔，徐晃，曹爽，孙鲁育等强控制型武将

]]
-- 反贼选将禁表，要用name区分
-- 印锦囊，跳阶段，无限翻面，砍体力上限，秒杀，变更势力，改身份牌，
local rebel_generals_blacklist = {"daqiao","hs__daqiao","ex__daqiao", "mou__daqiao", "xuhuang", "hs__xuhuang", "caoshuang","os__yangyi",
"yangbiao","js__yangbiao","manchong","m_ex__manchong","xinpi","mobile__caosong","ol__sunluyu","sunluyu","godsunce","mobile__duyu",
"lingju","ol__dongzhao","wenyang","os__godguanyu","godguanyu","ol__mengda","js__lvbu",
"moe__chuxiao","moe__ruanruan","sw_huiyeji","sw_fuji","sw_zeniya",
}

-- 主选将白名单，指不满足选将限制也会出现在选将列表中，主要是蜀国神将
local lord_generals_whitelist = {"godliubei" , "os__godguanyu" , "godzhangfei" , "godjiangwei" , "godmachao" , "godzhugeliang"}

local lord_generals_blacklist = {""}

-- 牌堆黑名单
local drawpile_blacklist = { "indulgence", "supply_shortage"}



local kfzy_getLogic = function()
  local kfzy_logic = GameLogic:subclass("kfzy_logic")

  function kfzy_logic:assignRoles() -- 分配身份
    local room = self.room
    local n = #room.players

    for i = 1, n do
      local p = room.players[i]
      if i == 1 then
        p.role = "lord"
      else
        p.role = "rebel"
      end
      p.role_shown = true
      room:broadcastProperty(p, "role")
    end

  end

  function kfzy_logic:prepareDrawPile() -- 准备牌堆，主要是BAN禁卡
    local room = self.room
    local allCardIds = Fk:getAllCardIds()
    local blacklist = drawpile_blacklist
    local whitelist = {""}
    for i = #allCardIds, 1, -1 do
      local card = Fk:getCardById(allCardIds[i])
      local name = card.name
      if (card.is_derived and not table.contains(whitelist, name)) or table.contains(blacklist, name) then
        local id = allCardIds[i]
        table.removeOne(allCardIds, id)
        table.insert(room.void, id)
        room:setCardArea(id, Card.Void, nil)
      end
    end
  
    table.shuffle(allCardIds)
    room.draw_pile = allCardIds
    for _, id in ipairs(room.draw_pile) do
      room:setCardArea(id, Card.DrawPile, nil)
    end
  end

  function kfzy_logic:chooseGenerals() -- 准备选将
    local room = self.room
    local generalNum = room.settings.generalNum
    local n = room.settings.enableDeputy and 2 or 1
    local lord = room:getLord()
    
    -- 主公选将
    local lord_generals
    if lord ~= nil then
      room.current = lord

      local generals = Fk:getGeneralsRandomly(generalNum, Fk:getAllGenerals(), nil, function(g)
        return not (g.kingdom == "shu" or (g.subkingdom and g.subkingdom == "shu") or table.contains(lord_generals_whitelist, g.name))
        or table.contains(lord_generals_blacklist, g.name)
      end)
      local general_names = table.map(generals, function(g) return g.name end)
      lord_generals = room:askForGeneral(lord, general_names, n)
      local lord_general, deputy
      if type(lord_generals) == "table" then
        deputy = lord_generals[2]
        lord_general = lord_generals[1]
      else
        lord_general = lord_generals
        lord_generals = {lord_general}
      end
  
      room:setPlayerGeneral(lord, lord_general, true)
      room:broadcastProperty(lord, "general")
      room:setDeputyGeneral(lord, deputy)
      room:broadcastProperty(lord, "deputyGeneral")
      lord.kingdom = "shu"
      room:notifyProperty(lord, lord, "kingdom")
      room:broadcastProperty(lord, "kingdom")

    end
    
    -- 其他人选将
    local nonlord = room:getOtherPlayers(lord, true)
    local generals = Fk:getGeneralsRandomly(#nonlord * generalNum, Fk:getAllGenerals(), lord_generals, function(g)
      return g.kingdom == "shu" or (g.subkingdom and g.subkingdom == "shu" ) or table.contains(rebel_generals_blacklist, g.name)
    end)
    table.shuffle(generals)
    for _, p in ipairs(nonlord) do
      local arg = {}
      for i = 1, generalNum do
        table.insert(arg, table.remove(generals, 1).name)
      end
      p.request_data = json.encode{ arg, n }
      p.default_reply = table.random(arg, n)
    end

    room:doBroadcastNotify("ShowToast", Fk:translate("kfzy_intro"))

    room:notifyMoveFocus(nonlord, "AskForGeneral")
    room:doBroadcastRequest("AskForGeneral", nonlord)

    for _, p in ipairs(nonlord) do
      if p.general == "" and p.reply_ready then
        local _generals = json.decode(p.client_reply)
        local general = _generals[1]
        local deputy = _generals[2]
        room:setPlayerGeneral(p, general, true, true)
        room:setDeputyGeneral(p, deputy)
      else
        room:setPlayerGeneral(p, p.default_reply[1], true, true)
        room:setDeputyGeneral(p, p.default_reply[2])
      end
      p.default_reply = ""
    end

    room:askForChooseKingdom(table.filter(nonlord, function (p)
      return p.kingdom ~= "god" and Fk.generals[p.general].subkingdom
    end))
    for _, p in ipairs(nonlord) do
      if p.kingdom == "god" then
        local allKingdoms = table.filter({"wei", "wu", "qun", "jin" , "moe" , "que" }, 
        function(k) return table.contains(Fk.kingdoms, k) end)
        p.kingdom = table.random(allKingdoms)
        room:notifyProperty(p, p, "kingdom")
        room:broadcastProperty(p, "kingdom")
      end
    end
  end

  function kfzy_logic:broadcastGeneral() -- 构件武将，在这里改血
    local room = self.room
    local players = room.players
  
    for _, p in ipairs(players) do
      assert(p.general ~= "")
      local general = Fk.generals[p.general]
      local deputy = Fk.generals[p.deputyGeneral]
      p.maxHp = p:getGeneralMaxHp()
      p.hp = deputy and math.floor((deputy.hp + general.hp) / 2) or general.hp
      p.shield = math.min(general.shield + (deputy and deputy.shield or 0), 5)
      -- TODO: setup AI here

      if p.role == "lord" then
        p.maxHp = 2 + #room.players
        p.hp = 2 + #room.players
        p.kingdom = "shu"
      else
        p.maxHp = 2
        p.hp = 2
      end
      room:broadcastProperty(p, "general")
      room:broadcastProperty(p, "deputyGeneral")
      room:broadcastProperty(p, "kingdom")
      room:broadcastProperty(p, "maxHp")
      room:broadcastProperty(p, "hp")
      room:broadcastProperty(p, "shield")
    end
  end

  function kfzy_logic:attachSkillToPlayers() -- 增加技能
    local room = self.room
  
    local addRoleModSkills = function(player, skillName)
      local skill = Fk.skills[skillName]
      if skill.lordSkill and player.role ~= "lord" then
        return
      end
      if #skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, player.kingdom) then
        return
      end
      room:handleAddLoseSkills(player, skillName, nil, false)
    end

    for _, p in ipairs(room.alive_players) do
      local skills = Fk.generals[p.general].skills
      for _, s in ipairs(skills) do
        addRoleModSkills(p, s.name)
      end
      for _, sname in ipairs(Fk.generals[p.general].other_skills) do
        addRoleModSkills(p, sname)
      end
      local deputy = Fk.generals[p.deputyGeneral]
      if deputy then
        skills = deputy.skills
        for _, s in ipairs(skills) do
          addRoleModSkills(p, s.name)
        end
        for _, sname in ipairs(deputy.other_skills) do
          addRoleModSkills(p, sname)
        end
      end
      if p.role == "lord" then
        room:handleAddLoseSkills(p, "kfzy_fuhan", nil, false)
      else
        room:handleAddLoseSkills(p, "kfzy_jiehuan", nil, false)
      end
    end
  end

  return kfzy_logic
end


local kfzy_rule = fk.CreateTriggerSkill{
  name = "#kfzy_rule",
  priority = 0.001,
  refresh_events = {fk.GameStart, fk.GameOverJudge, fk.BuryVictim, fk.Deathed, fk.RoundStart, fk.RoundEnd, fk.DrawInitialCards},
  can_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.RoundEnd then return room:getTag("RoundCount") == 9 end
    if event == fk.GameStart then return true end -- GameStart 时机的target只有当前回合者
    return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.GameStart then
      room:setTag("SkipNormalDeathProcess", true)
    elseif event == fk.GameOverJudge then
      -- 判断游戏结局 使用默认判定
      --[[
      room:setTag("SkipGameRule", true)
      if #room.alive_players == 1 then
        local winner = Fk.game_modes[room.settings.gameMode]:getWinner(player)
        if winner ~= "" then
          room:gameOver(winner)
          return true
        end
      end
      --]]
    elseif event == fk.BuryVictim then
      -- 死亡奖惩
      local damage = data.damage
      local victim = room:getPlayerById(data.who)
      if damage and damage.from and not damage.from.dead and damage.from then
        local killer = damage.from
        if killer.role == "lord" then
          if victim.role == "rebel" then
            killer:drawCards(1, "kill")
          elseif victim.role == "loyalist" then
            killer:throwAllCards("he")
          end
        elseif killer.role == "loyalist" and victim.role == "rebel" then
          local lord = room:getLord()
          if lord then
            room:recover { num = 1, skillName = self.name, who = lord , recoverBy = killer}
          end
        elseif killer.role == "rebel" and victim.role == "loyalist" then
          local num = #table.filter(room.players, function (p) return p.role == "loyalist"  end)
          killer:drawCards(num, "kill")
        end
      end
    elseif event == fk.Deathed then
      -- 死亡后额外效果，比奖惩晚
      -- 反贼加上复活标记，以及捡包回血
      if player.role == "rebel" then
        room:addPlayerMark(player, "@@RebelGuifu")
        local count = room:getTag("RebelDeathCount") or 0
        count = count + 1
        if count >= 2 or #room.alive_players <= 4 then
          for _, p in ipairs(room.alive_players) do
            if p.role == "rebel" and not p.dead then
              room:changeMaxHp(p, 1)
              room:recover { num = 1, skillName = self.name, who = p , recoverBy = p}
              p:drawCards(1, self.name)
            end
          end
          count = 0
        end
        room:setTag("RebelDeathCount", count)
        local lord = room:getLord()
        if lord then
          room:changeMaxHp(lord, -1)
          local myskills = lord:getMark("kfzy_fuhan_skills")
          if type(myskills) == "table"  then
            myskills = table.filter(myskills, function (s) return lord:hasSkill(s, true) end) -- 筛选出被其他方式删掉的
            if #myskills > 0 then
              local choice = room:askForChoice(lord, myskills, self.name, "#ty__fuhan-delete", true)
              table.removeOne(myskills, choice)
              room:handleAddLoseSkills(lord, "-"..choice, nil, true, false)
            end
            room:setPlayerMark(lord, "kfzy_fuhan_skills", #myskills > 0 and myskills or 0)
          end
        end
      end
    elseif event == fk.RoundEnd then
      --第九轮反贼获胜
      room:gameOver("rebel")
    elseif event == fk.RoundStart then
      -- 复活反贼变身为忠臣（归服）
      local targets = table.filter(room.players, function (p) return p:getMark("@@RebelGuifu") > 0 end)
      for _, p in ipairs(targets) do
        room:setPlayerMark(p, "@@RebelGuifu", 0)
        room:handleAddLoseSkills(p, "-kfzy_jiehuan", nil, false)
        local gender = p.gender
        p.kingdom = "shu"
        p.role = "loyalist"
        p.maxHp = 2
        room:revivePlayer(p, true)
        p.hp = 2
        room:broadcastProperty(p, "role")
        room:broadcastProperty(p, "maxHp")
        room:broadcastProperty(p, "hp")
        room:setPlayerProperty(p, "kingdom", "shu")
        room:broadcastProperty(p, "kingdom")
        room:setPlayerProperty(p, "gender", gender)
        p:drawCards(3)
        room:delay(1200)
      end
    elseif event == fk.DrawInitialCards then
      --更改初始手牌，时机比七星早
      if player.role == "lord" then
        data.num = 3 + #room.alive_players
      else
        data.num = 3
      end
    end
  end,
}

Fk:addSkill(kfzy_rule)


local kfzy_mode = fk.CreateGameMode{
  name = "kfzy_mode",
  minPlayer = 4,
  maxPlayer = 8,
  rule = kfzy_rule,
  logic = kfzy_getLogic,
  surrender_func = function(self, playedTime)
    local surrenderJudge = { { text = "time limitation: 2 min", passed = playedTime >= 120 } }
    return surrenderJudge
  end,
  --[[winner_getter = function(self, victim)
    return ""
  end,--]]
}

local kfzy_fuhan = fk.CreateTriggerSkill{
  name = "kfzy_fuhan",
  events = {fk.RoundStart },
  anim_type = "special",
  frequency = Skill.Compulsory,
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and (player.room:getTag("RoundCount") == 1 or type(player:getMark("kfzy_fuhan_skills") ) ~= "table")
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    if event == fk.RoundStart then
      if room:getTag("RoundCount") == 1 then
        local myskills = {}
        local skills = {}
        for _, general in pairs(Fk:getAllGenerals()) do
          if (not general.hidden and not general.total_hidden) and general.kingdom == "shu" then
            for _, skill_name in ipairs(general:getSkillNameList()) do
              local skill = Fk.skills[skill_name]
              if not player:hasSkill(skill, true, true) and not (skill.lordSkill or skill.switchSkillName or skill.frequency > 3) and
              not (#skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, "shu") )  then
                table.insertIfNeed(skills, skill.name)
              end
            end
          end 
        end
        for _ = 1, 3 do
          if #skills == 0 then break end
          local _skills = table.random(skills, 3)
          local choice = room:askForChoice(player, _skills, self.name, "#ty__fuhan-choice", true)
          table.insert(myskills, choice)
          table.removeOne(skills, choice)
          room:handleAddLoseSkills(player, choice, nil, true, false)
        end
        room:setPlayerMark(player, "kfzy_fuhan_skills", #myskills > 0 and myskills or 0)
      end
      if type(player:getMark("kfzy_fuhan_skills") ) ~= "table"  then
        local tos = table.filter(player.room.alive_players, function(p) return p.role == "rebel" and not player:isProhibited(p, Fk:cloneCard("slash")) end)
        if #tos > 0 then
          room:useVirtualCard("slash", nil, player, table.random(tos), self.name, true)
        end
      end
    end
  end,
}
Fk:addSkill(kfzy_fuhan)

local kfzy_jiehuan = fk.CreateTriggerSkill{
  name = "kfzy_jiehuan",
  anim_type = "defensive",
  events = {fk.DamageInflicted}, -- 受到伤害时
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and target == player and data.from and data.from ~= player and data.from.role == "rebel"
    and not player:isNude() and player:usedSkillTimes(self.name, Player.HistoryRound) == 0
  end,
  on_cost = function(self, event, target, player, data)
    return #player.room:askForDiscard(player, 1, 1, true, self.name, true, ".", "#kfzy_jiehuan") > 0
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:doIndicate(player.id, {data.from.id})
    return true
  end,
}
local kfzy_jiehuan_maxcards = fk.CreateMaxCardsSkill{
  name = "#kfzy_jiehuan_maxcards",
  correct_func = function(self, player)
    -- Fk:currentRoom() 不能 getLord() 好无语
    if player:hasSkill("kfzy_jiehuan") then
      return table.find(Fk:currentRoom().alive_players, function (p)
        return p.role == "lord" and player:inMyAttackRange(p) 
      end) and 0 or 2
    else
      return 0
    end
  end,
}
kfzy_jiehuan:addRelatedSkill(kfzy_jiehuan_maxcards)

Fk:addSkill(kfzy_jiehuan)





Fk:loadTranslationTable{
  ["kfzy_mode"] = "克复中原",
  [":kfzy_mode"] = desc_kfzy,
  ["kfzy"] = "克复中原",
  ["@@RebelGuifu"] = "归服",
  ["#kfzy_rule"] = "克复中原规则",
  ["kfzy_fuhan"] = "复汉",
  [":kfzy_fuhan"] = "锁定技，第一轮开始时，你重复三次：从随机的3个蜀国武将技能中选择一个获得。每轮开始时，若你已失去以此法获得的所有技能，你视为对随机一名反贼角色使用了一张【杀】。",
  ["kfzy_jiehuan"] = "结患",
  [":kfzy_jiehuan"] = "每轮限一次，你受到其他反贼造成的伤害时，你可以弃置一张牌防止此伤害。锁定技，若你攻击范围不含主公，你的手牌上限+2。",
  ["#kfzy_jiehuan"] = "结患：你可以弃置一张牌防止此伤害",
  ["#ty__fuhan-choice"] = "复汉：从随机的3个蜀国武将技能中选择一个获得",
  ["#ty__fuhan-delete"] = "复汉：失去一个“复汉”获得的技能",
  ["kfzy_intro"] = "北伐开始！",
}

return kfzy_mode
